﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows.Threading;

namespace LogoFX.Controls
{
    public sealed class NotificationsService
    {
        #region Fields

        private static readonly Lazy<NotificationsService> s_instance = 
            new Lazy<NotificationsService>(() => new NotificationsService());

        private readonly List<Notification> _closing = new List<Notification>();

        #endregion

        #region Constructors

        private NotificationsService()
        {
            Notifications = new ObservableCollection<Notification>();
            TimeToNitificationRelease = TimeSpan.FromSeconds(10);
        }

        #endregion

        #region Events

        public event EventHandler<NotificationServiceItemEventArgs> NotificationShowing;

        public event EventHandler<NotificationServiceItemEventArgs> NotificationClosing;

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets single instance of the <see cref="NotificationsService"/> class.
        /// </summary>
        public static NotificationsService Instance
        {
            get { return s_instance.Value; }
        }

        public ObservableCollection<Notification> Notifications { get; private set; }

        public TimeSpan TimeToNitificationRelease { get; set; }

        #endregion

        #region Public Methods

        public void Show(object cookie, object dataObject)
        {
            Notification notification = Notifications
                .SingleOrDefault(x => x.Cookie.Equals(cookie) && !_closing.Contains(x));

            if (notification != null)
            {
                int index = Notifications.IndexOf(notification);
                Notifications.RemoveAt(index);
                notification.DataObject = dataObject;
                Notifications.Insert(index, notification);
            }
            else
            {
                notification = new Notification(cookie, dataObject, TimeToNitificationRelease);
                Notifications.Add(notification);
            }

            OnNotificationShowing(new NotificationServiceItemEventArgs(notification));
        }

        public void StartHide(object cookie)
        {
            Notification notification = Notifications.SingleOrDefault(x => x.Cookie.Equals(cookie));

            if (notification == null)
            {
                return;
            }

            OnNotificationClosing(new NotificationServiceItemEventArgs(notification));
        }

        public void Hide(object cookie)
        {
            Notification notification = _closing.SingleOrDefault(x => x.Cookie.Equals(cookie));

            if (notification == null)
            {
                notification = Notifications.SingleOrDefault(x => x.Cookie.Equals(cookie));
            }
                
            if (notification == null)
            {
                return;
            }

            Notifications.Remove(notification);
            _closing.Remove(notification);
        }

        internal void StartClose(Notification notification)
        {
            _closing.Add(notification);
        }

        #endregion

        #region Private Members

        private void OnNotificationShowing(NotificationServiceItemEventArgs e)
        {
            if (NotificationShowing != null)
            {
                NotificationShowing(this, e);
            }
        }

        private void OnNotificationClosing(NotificationServiceItemEventArgs e)
        {
            if (NotificationClosing != null)
            {
                NotificationClosing(this, e);
            }
        }

        #endregion
    }
}